//////////////////////////////////////////////////////////////////////////////////////////////////
//  Date    : 2021/7/9                                                                           //
//  Author  : Jack.Pan                                                                          //
//  Desc    : Virtual FIB bus connection of FIB bus                                             //
//  Version : 0.0(Orignal)                                                                      //
//备注：目前支持的传输有SIGR和SEQR，且SEQR的长度不超过128次Burst
//////////////////////////////////////////////////////////////////////////////////////////////////
module VirtualFIB(
//------------FIB bus interface--------------
    input  wire             VFIBi_CLK,
    input  wire             VFIBi_ARST,
    input  wire             VFIBi_WREN,      //write to FIB enable
    input  wire             VFIBi_REQ,       //request FIB trans
    output  reg             VFIBo_ACK,       //request acknowledge
    output  reg             VFIBo_FULL,      //FIB FIFO full
    input  wire             VFIBi_ID,
    input  wire[7:0]        VFIBi_CMD,
    input  wire[3:0]        VFIBi_BURST,
    input  wire[3:0]        VFIBi_SIZE,
    input  wire[`XLEN-1:0]  VFIBi_ADDR,      
    input  wire[`XLEN-1:0]  VFIBi_DATA,
    output  reg[7:0]        VFIBo_ID,
    output  reg[7:0]        VFIBo_RPL,
    output  reg             VFIBo_V,
    output  reg[`XLEN-1:0]  VFIBo_DATA

    
);
parameter IDLE = 4'h0;
parameter STBY = 4'h1;
parameter SIGR = 4'h2;
parameter SEQR = 4'h3;
//-----------FIB Address and data register-------------
    reg [63:0]  rADDR;
    reg [63:0]  rDATA;
    reg [3:0]   rSIZE;
    reg [3:0]   rBURST;
    reg [7:0]   rID;
    reg [7:0]   rCMD;
//--------------read counter---------------------------
    reg [8:0]   ReadCounter;
//-----------Block RAM ---------------------------------
    reg [3:0]   VFIB_state;           //state of VFIB
    reg [63:0]  BRAM64[65535:0];      //16K Word * 8Byte RAM
initial
begin 
	$readmemh("bin.txt",BRAM64);
	#5 BRAMo <= 64'h0;
end
always@(posedge VFIBi_CLK or posedge ARST)begin
    if(VFIBi_ARST)begin
        ReadCounter <= 9'd0;
    end
    else if(VFIB_state==SEQR)begin
        ReadCounter <= ReadCounter + 9'd0;
    end
end
always@(posedge VFIBi_CLK or posedge ARST)begin
   if(VFIBi_ARST)begin
       VFIB_state <= IDLE;
   end 
   else begin
       case(VFIB_state)
        IDLE :  if(VFIBi_REQ)begin
                    VFIB_state <= STBY;
                end
        STBY :  if(VFIBi_WREN)begin
                    case(VFIBi_CMD)
                     `FIB_CMD_SIGR : VFIB_state <= SIGR;
                     `FIB_CMD_SEQR : VFIB_state <= SEQR;
                    endcase
                end
        SIGR :  VFIB_state <= IDLE;
        SEQR :  case(rSIZE)
                    2'd0 : VFIB_state <= IDLE;
                    2'd1 : VFIB_state <= (ReadCounter==9'd1) ? IDLE : VFIB_state;
                    2'd2 : VFIB_state <= (ReadCounter==9'd3) ? IDLE : VFIB_state;
                    2'd3 : VFIB_state <= (ReadCounter==9'd7) ? IDLE : VFIB_state;
                    2'd4 : VFIB_state <= (ReadCounter==9'd15) ? IDLE : VFIB_state;
                    2'd5 : VFIB_state <= (ReadCounter==9'd31) ? IDLE : VFIB_state;
                    2'd6 : VFIB_state <= (ReadCounter==9'd63) ? IDLE : VFIB_state;
                    2'd7 : VFIB_state <= (ReadCounter==9'd127) ? IDLE : VFIB_state;
                endcase
   end
end
//-------------Virtual FIB input registers---------------------
always@(posedge VFIBi_CLK or posedge VFIBi_ARST)begin
    if(VFIBi_ARST)begin
        rADDR <= 64'h0;
        rDATA <= 64'h0;
        rSIZE <= 4'h0;
        rBURST<= 4'h0;
        rCMD  <= `FIB_CMD_NOOP;
    end
//----------If VFIBi write enable, registered input signals---------
    else if(VFIBi_WREN)begin
        rADDR <= VFIBi_ADDR;
        rDATA <= VFIBi_DATA;
        rSIZE <= VFIBi_SIZE;
        rBURST<= VFIBi_BURST;
    end
end
//--------------Virtual FIB output Registers--------------------
// VFIB ACK
always@(*)begin
    if(state == SIGR)begin
        VFIBo_ACK <= 1'b1;
    end
    else if(state == SEQR)begin
        VFIBo_ACK <= 1'b1;
    end
    else begin
        VFIBo_ACK <= 1'b0;
    end
end
// VFIB ID Register
always@(posedge VFIBi_CLK or posedge VFIBi_ARST)begin
    if(VFIBi_ARST)begin
        VFIBo_ID <= 8'h00;
    end
    else if(VFIBi_WREN)begin            // VFIB Write Enable
        VFIBo_ID <= VFIBi_ID
    end
end
// VFIB V 
always@(*)begin
    if((state == SIGR))begin
        VFIBo_V <= 1'b1;
    end
    else if(state == SEGR)begin
        case(rSIZE)
            2'd0 : VFIBo_V <= IDLE;
            2'd1 : VFIBo_V <= (ReadCounter==9'd1) ? 1'b1 : 1'b0;
            2'd2 : VFIBo_V <= (ReadCounter==9'd3) ? 1'b1 : 1'b0;
            2'd3 : VFIBo_V <= (ReadCounter==9'd7) ? 1'b1 : 1'b0;
            2'd4 : VFIBo_V <= (ReadCounter==9'd15) ? 1'b1 : 1'b0;
            2'd5 : VFIBo_V <= (ReadCounter==9'd31) ? 1'b1 : 1'b0;
            2'd6 : VFIBo_V <= (ReadCounter==9'd63) ? 1'b1 : 1'b0;
            2'd7 : VFIBo_V <= (ReadCounter==9'd127) ? 1'b1 : 1'b0;
            default: VFIBo_V <= 1'b0;
        endcase
    end
end

// VFIB RPL register
always@(*)begin
    case(VFIB_state)
        IDLE : VFIBo_RPL <= `FIB_RPL_NOOP;      //state == Idle, reply == noop
        STBY : VFIBo_RPL <= `FIB_RPL_NOOP;
        SIGR : VFIBo_RPL <= `FIB_RPL_TRDY;
        SEQR : if(ReadCounter == 8'd63)begin
                    VFIBo_RPL <= `FIB_RPL_TRDY;
                end
                else begin
                    VFIBo_RPL <= `FIB_RPL_NOOP;
                end
        default: VFIBo_RPL <= `FIB_RPL_NOOP'
    endcase
end
//  VfiB output data registers
always@(*)begin
    VFIBo_DATA <= BRAM64 [rADDR + ReadCounter];     //Output data = base address + offset address
end
//  

endmodule